﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using Shared;
using System.Collections;

namespace Kea
{
    public abstract class DataPlanBaseTRW<TTRW> : DataPlanBase<TTRW> where TTRW : TableReaderWriter<TTRW>, new()
    {
        internal string IndexName { get; set; }
        internal object[] IndexValuesLowerLimit { get; set; }
        internal object[] IndexValuesUpperLimit { get; set; }

        internal bool LowerAndUpperIndexValuesMatch
        {
            get
            {
                if (IndexValuesLowerLimit == IndexValuesUpperLimit) return true;
                if (IndexValuesUpperLimit == null || IndexValuesLowerLimit == null) return false;
                if (IndexValuesLowerLimit.Length != IndexValuesUpperLimit.Length) return false;
                for (int i = 0; i < IndexValuesLowerLimit.Length; i++) if (IndexValuesLowerLimit[i] != IndexValuesUpperLimit[i]) return false;
                return true;
            }
        }

        protected override sealed IEnumerable<TTRW> SelectInternal()
        {
            using (var tm = new TRWManager<TTRW>(this)) while (tm.ReadInternal()) yield return tm.Item;
        }


        public new IEnumerable<TResult> Select<TResult>(Func<TTRW, TResult> selector)
        {
            return base.Select(selector);
        }

        protected DataPlanOrdered<TTRW> OrderByProtected<TKey>(Func<TTRW, TKey> keySelector, bool asc)
        {
            return new DataPlanOrdered<TTRW>
            {
                IndexName = IndexName,
                IndexValuesLowerLimit = IndexValuesLowerLimit,
                IndexValuesUpperLimit = IndexValuesUpperLimit,
                Comparer = new KeyComparerProvider<TTRW, TKey>(Comparer, p => keySelector(p), asc),
                Filters = Filters
            };
        }


        #region

        public EnumerableProvider<TTRW, TResult> GetEnumerableProvider<TResult>(Func<TTRW, TResult> selector)
        {
            return new EnumerableProvider<TTRW, TResult>(this, selector);
        }

        #endregion

    }

    public class EnumerableProvider<TTRW, TResult> : IDisposable where TTRW : TableReaderWriter<TTRW>, new()
    {
        private readonly Func<TTRW, TResult> _selector;
        private TRWManager<TTRW> _man;
        private DataPlanBaseTRW<TTRW> _dataPlan;
        private Key _keyConverter = new Key();
        private object[] _key;
        internal EnumerableProvider(DataPlanBaseTRW<TTRW> dataPlan, Func<TTRW, TResult> selector)
        {
            _dataPlan = dataPlan;
            _selector = selector;
        }

        public void Dispose()
        {
            if (_man == null) return;
            ((IDisposable)_man).Dispose();
            _man = null;
        }

        private EnumerableX _enumerable;
        public EnumerableX GetEnumerable(object indexValue)
        {
            _key = _keyConverter.GetKey(indexValue);

            if (_man == null)
            {
                _man = new TRWManager<TTRW>(_dataPlan);
                _man.LoadIndexDetails();
            }

            _readState = ReadState.HaveNotStarted;
            return _enumerable ?? (_enumerable = new EnumerableX() { EnumerableProvider = this });
        }
        private ReadState _readState;
        internal bool MoveNext()
        {
            if (_readState == ReadState.HaveValue)
            {
                if (_man.ReadNextInRange(_key)) return true;
                _readState = ReadState.EndOfValues;
                return false;
            }

            if (_readState == ReadState.HaveNotStarted)
            {
                if (_man.ReadToStartOfRange(_key))
                {
                    _readState = ReadState.HaveValue;
                    return true;
                }
                else
                {
                    _readState = ReadState.EndOfValues;
                    return false;
                }
            }

            throw new Exception("No more values.");
        }
        private enum ReadState : byte { HaveNotStarted = 0, HaveValue, EndOfValues }
        internal TResult Current { get { return _selector(_man.Item); } }
        internal void Reset() { _readState = ReadState.HaveNotStarted; }


        public class EnumerableX : IEnumerable<TResult>
        {
            internal EnumerableProvider<TTRW, TResult> EnumerableProvider;
            public Enumerator GetEnumerator()
            {
                return new Enumerator() { EnumerableProvider = EnumerableProvider };
            }

            IEnumerator IEnumerable.GetEnumerator()
            {
                return GetEnumerator();
            }

            IEnumerator<TResult> IEnumerable<TResult>.GetEnumerator()
            {
                return GetEnumerator();
            }
        }

        public struct Enumerator : IEnumerator<TResult>
        {
            internal EnumerableProvider<TTRW, TResult> EnumerableProvider;

            object IEnumerator.Current { get { return Current; } }
            void IDisposable.Dispose() { }
            bool IEnumerator.MoveNext() { return MoveNext(); }
            void IEnumerator.Reset() { Reset(); }

            public TResult Current { get { return EnumerableProvider.Current; } }
            public bool MoveNext() { return EnumerableProvider.MoveNext(); }
            public void Reset() { EnumerableProvider.Reset(); }
            void Dispose() { }
        }

        //        public Enumerator GetEnumerator() { }


    }



}
